#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# :CREATED: [2018-01-04 四 07:17]
# :AUTHOR: zb
import os
from untils import encode_code, log
from models import User
import time

session = {
    'session_id': {
        'username': 'haha',
        'userid': -1,
        'timeout': 1231232132,
    },
}


def read_picture(name, path='static'):
    p = path + os.sep + name
    with open(p, 'rb') as f:
        return f.read()


def template(filename, path='templates'):
    p = path + os.sep + filename
    with open(p, 'r', encoding=encode_code) as f:
        return f.read()


def error_static(request, code=404):
    '''
    根据code 的不同,返回不同的错误响应
    '''
    d = {404: '<h1>404! page not found</h1>', 501: 'server busy!'}
    body = d.get(code, '')
    return response_with_headers(body, response_code=code)


def set_passwd(passwd):
    """
    Keyword Arguments:
    passwd -- the original string
    return hashed string
    """
    return passwd


def current_user(request):
    """
    Keyword Arguments:
    request --
    """
    session_id = request.cookie.get('user', )
    username = session.get(session_id, {}).get('username', '游客')
    log('current_user -- session : {}\nquery session_id : {}'.format(
        session, session_id))
    return username


def current_userid(request):
    """
    Keyword Arguments:
    request --
    """
    session_id = request.cookie.get('user', )
    username = session.get(session_id, {}).get('userid', -1)
    return username


def set_header(headers={}, code='200', code_name='ok'):
    """
    Keyword Arguments:
    headers  --
    response --
    """
    h = {'Content-Type': 'text/html;charset={}'.format(encode_code)}
    h.update(headers)
    header = 'HTTP/1.1 {} {}\r\n'.format(code, code_name)
    header += ''.join(['{}: {}\r\n'.format(k, v) for k, v in h.items()])
    return header


def response_with_headers(body, headers={}, response_code=200):
    """
    Keyword Arguments:
    headers -- {}
    body    -- string
    """
    header = set_header(headers, code=response_code)
    if isinstance(body, bytes):
        r = header.encode(encode_code) + b'\r\n' + body
    else:
        r = header + '\r\n' + body
        r = r.encode(encode_code)
    return r


def redirect(url, *args, **kwgs):
    """
    Keyword Arguments:
    route -- new route to redirect
    """
    headers = {'location': url}
    r = response_with_headers('', headers=headers, response_code=302)
    return r


def set_session(user):
    """
    Keyword Arguments:
    user -- user is a obj
    """
    # TODO: 完善sessionid, 需要加盐
    timeout = 60 * 2
    session_id = str(time.time())
    session[session_id] = {
        'userid': user.id,
        'username': user.username,
        'timeout': time.time() + timeout,
    }
    cookie = 'user={}'.format(session_id)
    return cookie


def validate_login(route='/', method='not_necessary'):
    """
    decorator
    check if user logined
    route : redirect to argument
    method :
          necessary > user must logined ,else redirect to route
          not_necessary >  user must not logined ,else redirect to route
    """

    def decorator(function):
        def check(request):
            username = current_user(request)
            userid = current_userid(request)
            u = User.find_by(id=userid)
            log('validate_login,check, username from current_user:', username)
            log('validate_login,check, u :', u)
            if method == 'necessary':
                if u == []:
                    log('validate route -- \n Destination {} ,'
                        ' necessary login ,redirect to {}'.format(
                            request.path, route))
                    return redirect(route, request=request)
                else:
                    log('validate route -- \n Destination {} ,'
                        ' necessary login'.format(request.path))
                    return function(request)
            elif method == 'not_necessary':
                if u == []:
                    log('validate route -- \n Destination {} ,'
                        ' not necessary login'.format(request.path))
                    return function(request)
                else:
                    log('validate route -- \n Destination {} ,'
                        ' not necessary login ,redirect to {}'.format(
                            request.path, route))
                    return redirect(route, request=request)
            else:
                log('validate route -- \n get unkown method {} ,'
                    ' redirect to {}'.format(method, route))
                return redirect(route, request=request)

        return check

    return decorator


def logout(request):
    '''
    logout, delete the seesion id
    '''
    session_id = request.cookie.get('user', )
    if session.get(session_id):
        session.pop(session_id)
    return redirect('/', request=request)


@validate_login(route='/')
def login(request):
    body = template('login.html')
    username = current_user(request)
    headers = {}
    if request.method == 'GET':
        result = ''
    else:
        form = request.form()
        log('login request form ', form, level='debug')
        u = User.new(form)
        if u.validate_resigter():
            if u.validate_login():
                result = '登录成功!,欢迎你{}'.format(u.username)
                username = u.username
                cookie = set_session(u)
                headers['Set-Cookie'] = cookie
            else:
                result = '登录失败, 密码错误!'
        else:
            result = '用户未注册!'
    body = body.replace('{{result}}', result)
    body = body.replace('{{username}}', username)
    return response_with_headers(body, headers=headers)


def validate_passwd(passwd):
    """
    Keyword Arguments:
    passwd -- user input passwd
    return if the passwd is valid.
    """
    return len(passwd) > 6


@validate_login(route='/')
def register(request):
    log('request.method', request.method)
    log('get cookie:', request.cookie)
    username = current_user(request)
    if request.method == 'GET':
        result = ''
    else:
        form = request.form()
        log('resigter request form ', form, level='debug')
        u = User.new(form)
        if u.validate_resigter():
            result = '{} 用户名已存在!'.format(u.username)
        else:
            if not validate_passwd(u.passwd):
                result = '密码长度必须大于等于6位!'
            else:
                u.passwd = set_passwd(u.passwd)
                u.save()
                result = '你已注册成功,欢迎你{}'.format(u.username)
                username = u.username
    body = template('register.html')
    body = body.replace('{{result}}', result)
    body = body.replace('{{username}}', username)
    return response_with_headers(body)


@validate_login('/', method='necessary')
def change_passwd(request):
    """
    Keyword Arguments:
    request -- the request obj
    post meth to modify passwd ,body like
    'oldPasswd=123&newPasswd=321'
    """
    body = template('changePasswd.html')
    username = current_user(request)
    userid = current_userid(request)
    body = body.replace('{{username}}', username)
    form = request.form()
    log('chage_passwd: \nrequest.method :{}\n request.form: {}\n'.format(
        request.method, form))
    if request.method == 'GET':
        return response_with_headers(body)
    elif request.method == 'POST':
        old_Passwd = form.get('oldPasswd', '')
        new_Passwd = form.get('newPasswd', '')

        u = User.find_by(id=userid).pop(0)
        if u.passwd == set_passwd(old_Passwd):
            if validate_passwd(new_Passwd):
                u.passwd = set_passwd(new_Passwd)
                u.save()
                logout(request)
                result = 'change passwd susssful!'
            else:
                result = 'the new passwd is invalid !'
        else:
            result = 'the old passwd is invalid !'
        body = body.replace('{{result}}', result)
        return response_with_headers(body)
    else:
        return error_static(request, code=404)


def route_index(request):
    body = template('index.html')
    username = current_user(request)
    body = body.replace('{{username}}', username)
    return response_with_headers(body)


def route_static(request):
    if request.method == 'GET':
        file_name = request.query.get('file', 'doge.gif')
        body = read_picture(file_name)
    else:
        body = b''
    return response_with_headers(body)


route_dict = {
    '/': route_index,
    '/static': route_static,
    '/login': login,
    '/register': register,
    '/logout': logout,
    '/changePasswd': change_passwd,
}
